package com.ssm.jvm.classloader;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;

public class ClassLoaderTest extends ClassLoader {

    private String rxRootPath;

    public ClassLoaderTest(String rxRootPath) {
        this.rxRootPath = rxRootPath;
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            // 原双亲委派逻辑代码位置
            if (c == null) {
                // If still not found, then invoke findClass in order
                // to find the class.
                long t1 = System.nanoTime();

                // 如果是不是自定义的 com.ssm 使用默认的类加载， 否则采用自定义类加载器
                if (!name.startsWith("com.ssm") ) {
                    c = this.getParent().loadClass(name);
                } else {
                    c = findClass(name);
                }

                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }



    @Override
    public Class findClass(String name) {
        byte[] b = loadClassData(name);
        return defineClass(name, b, 0, b.length);
    }

    /**
     * 读取 .class 文件为字节数组
     *
     * @param name 全路径类名
     * @return
     */
    private byte[] loadClassData(String name) {
        try {
            String filePath = fullClassName2FilePath(name);
            InputStream is = new FileInputStream(new File(filePath));
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] buf = new byte[2048];
            int r;
            while ((r = is.read(buf)) != -1) {
                bos.write(buf, 0, r);
            }
            return bos.toByteArray();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 全限定名转换为文件路径
     *
     * @param name
     * @return
     */
    private String fullClassName2FilePath(String name) {
        String fullClassPath = rxRootPath + name.replace(".", "//") + ".class";
        System.out.println(fullClassPath);
        return fullClassPath;
    }

    public static void main(String[] args) throws Exception {

        /*
        ClassLoaderTest classLoader = new ClassLoaderTest("/Users/zhengsh/Desktop/classapp/core/");
        String className =  "java.lang.String";

        Class clazz = classLoader.loadClass(className);
        */

        ClassLoaderTest classLoader = new ClassLoaderTest("/Users/zhengsh/Desktop/classapp/v1/");
        String className =  "com.ssm.Test";

        Class clazz = classLoader.loadClass(className);
        System.out.println(clazz.getClassLoader());
        Object obj = clazz.newInstance();
        Method method = clazz.getDeclaredMethod("outHello", null);
        method.invoke(obj, null);

        ClassLoaderTest classLoader1 = new ClassLoaderTest("/Users/zhengsh/Desktop/classapp/v2/");
        String className1 = "com.ssm.Test";

        Class clazz1 = classLoader1.loadClass(className1);
        System.out.println(clazz1.getClassLoader());
        Object obj1 = clazz1.newInstance();
        Method method1 = clazz1.getDeclaredMethod("outHello", null);
        method1.invoke(obj1, null);
    }
}